﻿using Application_Core.Kunde_Component.Access_Layer.Exceptions;
using Application_Core.Kunde_Component.Data_Access_Layer;
using Application_Core.Kunde_Component.Data_Access_Layer.Implementations;
using System.Collections.Generic;
using Utility.Global.Utilities;
using Utility.Persistence_Service;

namespace Application_Core.Kunde_Component.Access_Layer
{
    public class KundeComponentFacade : KundeService, KundeInternalService
    {
        private readonly KundeRepository kundeRepo;
        private readonly UnitOfWork unitOfWork;

        public KundeComponentFacade(UnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
            this.kundeRepo = new KundeRepositoryImpl(unitOfWork);
        }

        public void CreateKunde(KundeDTO kundeDTO)
        {
            Check.Argument(kundeDTO != null, "DataTransferObjekt von Kunde wird benötigt.");
            Check.Argument(kundeDTO.Nummer > 0, "Kundennummer muss positiv sein.");
            Check.Argument(!string.IsNullOrEmpty(kundeDTO.Nachname), "Nachname muss angegeben sein.");

            Kunde kunde = kundeDTO.ToEntity();
            this.kundeRepo.Create(kunde);
        }

        public void CreateOrUpdateKunde(KundeDTO kundeDTO)
        {
            Check.Argument(kundeDTO != null, "DataTransferObjekt von Kunde wird benötigt.");
            Check.Argument(kundeDTO.Nummer > 0, "Kundennummer muss positiv sein.");
            Check.Argument(!string.IsNullOrEmpty(kundeDTO.Nachname), "Nachname muss angegeben sein.");

            Kunde kunde = this.kundeRepo.FindByNummer(kundeDTO.Nummer);
            if (kunde != null) {
                kunde.Vorname = kundeDTO.Vorname;
                kunde.Nachname = kundeDTO.Nachname;
                kunde.Adresse = kundeDTO.Adresse.ToEntity();
                this.kundeRepo.Update(kunde);
            }
            else
            {
                this.kundeRepo.Create(kundeDTO.ToEntity());
            }
        }

        public KundeDTO FindKunde(int nummer)
        {
            Check.Argument(nummer > 0, "Kundennummer muss positiv sein.");

            Kunde kunde = this.kundeRepo.FindByNummer(nummer);
            if (kunde == null)
            {
                return null;
            }
            return kunde.ToDTO();
        }

        public List<KundeDTO> FindKunden(string nachname)
        {
            Check.Argument(nachname != string.Empty, "Nachname muss angegeben sein.");

            List<Kunde> kunden = this.kundeRepo.FindByNachname(nachname);
            List<KundeDTO> kundenDTOs = new List<KundeDTO>();
            foreach (Kunde kunde in kunden)
            {
                kundenDTOs.Add(kunde.ToDTO());
            }
            return kundenDTOs;
        }

        public void DeleteKunde(int nummer)
        {
            Check.Argument(nummer > 0, "Kundennummer muss positiv sein.");

            Kunde kunde = this.kundeRepo.FindByNummer(nummer);
            this.kundeRepo.Delete(kunde);
        }

        #region Internal

        public int FindIdByNummer(int nummer)
        {
            Check.Argument(nummer > 0, "Kundennummer muss positiv sein.");
            int? kundeIdNullable = this.kundeRepo.FindIdByNummer(nummer);
            if (kundeIdNullable == null)
            {
                throw new KundeNotFoundException("Kunde mit Nummer " + nummer + " konnte nicht gefunden werden.");
            }
            return (int)kundeIdNullable;
        }

        #endregion
    }
}
